package com.anli.xianliu;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.script.DefaultRedisScript;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import java.util.Collections;
import java.util.concurrent.TimeUnit;

/**
 * @author: LCG
 * 作者: LCG
 * 日期: 2021/3/8  8:33
 * 描述:
 */
@Aspect
@Component
public class LimitAop {

    @Autowired
    private RedisTemplate<String,Object> myRedisTemplate;

    //定义切面和切面表达式
    @Pointcut("execution(public * com.anli.web.TestXianLiuController.*(..))")
    public void aop(){

    }




    //组装切面定义通知类型
    @Around("aop() && @annotation(com.anli.xianliu.LimitInterface)")
    public Object myArround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {

        //获取AOP方法的注解
        MethodSignature signature = (MethodSignature) proceedingJoinPoint.getSignature();
        LimitInterface declaredAnnotation = signature.getMethod().getDeclaredAnnotation(LimitInterface.class);

        //获取注解的参数值Collections.singletonList(limitKey1)   list<String>
        String limitKey1 = declaredAnnotation.limitKey();
        int limitRate = declaredAnnotation.limitRate();
        int expire = declaredAnnotation.limitExpire();

        String lua="local count=redis.call('incr',KEYS[1]) if count == 1 then redis.call('expire',KEYS[1],ARGV[1]) return 0 elseif count > tonumber(ARGV[2]) then return 1 else return 0 end";

        DefaultRedisScript<Long> defaultRedisScript=new DefaultRedisScript<>();
        defaultRedisScript.setScriptText(lua);
        defaultRedisScript.setResultType(Long.class);

        Long execute = myRedisTemplate.execute(defaultRedisScript, Collections.singletonList(limitKey1), expire, limitRate);

        if(execute == 0){
            //通过切面
            return proceedingJoinPoint.proceed();
        }else{
            //阻止通过切面
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            requestAttributes.getResponse().getWriter().append("is limited");
            return null;
        }

       /* Long limitKey = redisTemplate.opsForValue().increment(limitKey1, 1);
        if(limitKey==1){
            redisTemplate.expire(limitKey1,expire,TimeUnit.SECONDS);
        }

        //2判断自增的值是不是大于 限流的速率 如果大于则直接返回 否则通过限流
        if(limitKey>limitRate){
           //阻止通过切面
            ServletRequestAttributes requestAttributes = (ServletRequestAttributes)RequestContextHolder.getRequestAttributes();
            requestAttributes.getResponse().getWriter().append("is limited");
            return null;
        }else{
            //通过切面
           return proceedingJoinPoint.proceed();
        }*/

    }

}
